package com.example.baselibrary.utlis

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.RequiresApi
import java.util.concurrent.CopyOnWriteArrayList

/**
 * 实时网络状态检测工具
 * 监听网络状态变化并实时反馈给观察者
 */
class NetworkMonitor private constructor() {

    private var connectivityManager: ConnectivityManager? = null
    private var networkCallback: ConnectivityManager.NetworkCallback? = null
    private val observers = CopyOnWriteArrayList<NetworkObserver>()
    private var currentNetworkType: Int = NETWORK_TYPE_NONE
    private var isNetworkAvailable: Boolean = false

    companion object {
        @Volatile
        private var instance: NetworkMonitor? = null

        fun getInstance(): NetworkMonitor = instance ?: synchronized(this) {
            instance ?: NetworkMonitor().also { instance = it }
        }

        // 网络类型常量
        const val NETWORK_TYPE_NONE = 0
        const val NETWORK_TYPE_WIFI = 1
        const val NETWORK_TYPE_MOBILE = 2
        const val NETWORK_TYPE_ETHERNET = 3
        const val NETWORK_TYPE_OTHER = 4
    }

    interface NetworkObserver {
        /**
         * 网络连接状态改变回调
         * @param isConnected 网络是否连接
         * @param networkType 网络类型
         * @param networkName 网络类型名称
         */
        fun onNetworkStatusChanged(isConnected: Boolean, networkType: Int, networkName: String)

        /**
         * 网络连接建立回调
         * @param networkType 网络类型
         * @param networkName 网络类型名称
         */
        fun onNetworkConnected(networkType: Int, networkName: String)

        /**
         * 网络连接断开回调
         */
        fun onNetworkDisconnected()

        /**
         * 网络类型改变回调
         * @param oldType 旧网络类型
         * @param newType 新网络类型
         * @param newName 新网络类型名称
         */
        fun onNetworkTypeChanged(oldType: Int, newType: Int, newName: String)
    }

    /**
     * 初始化网络监听器
     */
    fun initialize(context: Context) {
        if (connectivityManager != null) return

        connectivityManager =
            context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        currentNetworkType = getNetworkType()
        isNetworkAvailable = isNetworkAvailable()

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            registerNetworkCallback()
        }
    }

    /**
     * 注册网络状态回调
     */
    @RequiresApi(Build.VERSION_CODES.N)
    private fun registerNetworkCallback() {
        val networkRequest = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
            .build()

        networkCallback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                super.onAvailable(network)
                handleNetworkAvailable()
            }

            override fun onLost(network: Network) {
                super.onLost(network)
                handleNetworkLost()
            }

            override fun onCapabilitiesChanged(
                network: Network,
                networkCapabilities: NetworkCapabilities
            ) {
                super.onCapabilitiesChanged(network, networkCapabilities)
                handleNetworkCapabilitiesChanged()
            }
        }

        connectivityManager?.registerNetworkCallback(networkRequest, networkCallback!!)
    }

    /**
     * 处理网络可用事件
     */
    private fun handleNetworkAvailable() {
        val newNetworkType = getNetworkType()
        val isNowAvailable = isNetworkAvailable()

        if (!isNetworkAvailable && isNowAvailable) {
            isNetworkAvailable = true
            currentNetworkType = newNetworkType

            val networkName = getNetworkTypeName(newNetworkType)

            // 通知所有观察者网络已连接
            observers.forEach { observer ->
                observer.onNetworkConnected(newNetworkType, networkName)
                observer.onNetworkStatusChanged(true, newNetworkType, networkName)
            }
        } else if (isNetworkAvailable && isNowAvailable && newNetworkType != currentNetworkType) {
            // 网络类型改变
            val oldType = currentNetworkType
            currentNetworkType = newNetworkType
            val newName = getNetworkTypeName(newNetworkType)

            observers.forEach { observer ->
                observer.onNetworkTypeChanged(oldType, newNetworkType, newName)
                observer.onNetworkStatusChanged(true, newNetworkType, newName)
            }
        } else if (isNowAvailable) {
            // 网络状态更新
            val networkName = getNetworkTypeName(newNetworkType)
            observers.forEach { observer ->
                observer.onNetworkStatusChanged(true, newNetworkType, networkName)
            }
        }
    }

    /**
     * 处理网络丢失事件
     */
    private fun handleNetworkLost() {
        // 检查是否还有其他网络连接
        val isStillAvailable = isNetworkAvailable()

        if (isNetworkAvailable && !isStillAvailable) {
            isNetworkAvailable = false
            currentNetworkType = NETWORK_TYPE_NONE

            // 通知所有观察者网络已断开
            observers.forEach { observer ->
                observer.onNetworkDisconnected()
                observer.onNetworkStatusChanged(false, NETWORK_TYPE_NONE, "无网络")
            }
        } else if (isStillAvailable) {
            // 网络类型可能改变了
            val newNetworkType = getNetworkType()
            if (newNetworkType != currentNetworkType) {
                val oldType = currentNetworkType
                currentNetworkType = newNetworkType
                val newName = getNetworkTypeName(newNetworkType)

                observers.forEach { observer ->
                    observer.onNetworkTypeChanged(oldType, newNetworkType, newName)
                    observer.onNetworkStatusChanged(true, newNetworkType, newName)
                }
            }
        }
    }

    /**
     * 处理网络能力改变事件
     */
    private fun handleNetworkCapabilitiesChanged() {
        val newNetworkType = getNetworkType()
        val isNowAvailable = isNetworkAvailable()

        if (isNowAvailable != isNetworkAvailable) {
            if (isNowAvailable) {
                handleNetworkAvailable()
            } else {
                handleNetworkLost()
            }
        } else if (isNowAvailable && newNetworkType != currentNetworkType) {
            handleNetworkAvailable()
        }
    }

    /**
     * 添加网络状态观察者
     */
    fun addObserver(observer: NetworkObserver) {
        if (!observers.contains(observer)) {
            observers.add(observer)
        }
    }

    /**
     * 移除网络状态观察者
     */
    fun removeObserver(observer: NetworkObserver) {
        observers.remove(observer)
    }

    /**
     * 移除所有观察者
     */
    fun removeAllObservers() {
        observers.clear()
    }

    /**
     * 获取当前网络类型
     */
    fun getNetworkType(): Int {
        val cm = connectivityManager ?: return NETWORK_TYPE_NONE
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val activeNetwork = cm.activeNetwork
            val networkCapabilities = cm.getNetworkCapabilities(activeNetwork)
            when {
                networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true -> NETWORK_TYPE_WIFI
                networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true -> NETWORK_TYPE_MOBILE
                networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) == true -> NETWORK_TYPE_ETHERNET
                networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) == true -> NETWORK_TYPE_OTHER
                else -> NETWORK_TYPE_NONE
            }
        } else {
            @Suppress("DEPRECATION")
            val activeNetworkInfo = cm.activeNetworkInfo
            when (activeNetworkInfo?.type) {
                ConnectivityManager.TYPE_WIFI -> NETWORK_TYPE_WIFI
                ConnectivityManager.TYPE_MOBILE -> NETWORK_TYPE_MOBILE
                ConnectivityManager.TYPE_ETHERNET -> NETWORK_TYPE_ETHERNET
                else -> NETWORK_TYPE_NONE
            }
        }
    }

    /**
     * 获取网络类型名称
     */
    fun getNetworkTypeName(networkType: Int): String {
        return when (networkType) {
            NETWORK_TYPE_WIFI -> "WiFi"
            NETWORK_TYPE_MOBILE -> "移动数据"
            NETWORK_TYPE_ETHERNET -> "以太网"
            NETWORK_TYPE_OTHER -> "其他网络"
            else -> "无网络"
        }
    }

    /**
     * 检查网络是否可用
     */
    fun isNetworkAvailable(): Boolean {
        val cm = connectivityManager ?: return false
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val activeNetwork = cm.activeNetwork
            val networkCapabilities = cm.getNetworkCapabilities(activeNetwork)
            networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true &&
                    networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
        } else {
            @Suppress("DEPRECATION")
            val activeNetworkInfo = cm.activeNetworkInfo
            activeNetworkInfo?.isConnected == true
        }
    }

    /**
     * 获取当前网络状态信息
     */
    fun getCurrentNetworkInfo(): NetworkInfo {
        val isConnected = isNetworkAvailable()
        val networkType = if (isConnected) getNetworkType() else NETWORK_TYPE_NONE
        val networkName = getNetworkTypeName(networkType)

        return NetworkInfo(
            isConnected = isConnected,
            networkType = networkType,
            networkName = networkName
        )
    }

    /**
     * 销毁网络监听器
     */
    fun destroy() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            networkCallback?.let { callback ->
                connectivityManager?.unregisterNetworkCallback(callback)
            }
        }
        removeAllObservers()
        connectivityManager = null
        networkCallback = null
        instance = null
    }

    /**
     * 网络信息数据类
     */
    data class NetworkInfo(
        val isConnected: Boolean,
        val networkType: Int,
        val networkName: String
    )
}
